
local Wheel = Wheel

local copyTable = Wheel.copyTable

-- trackSelf: track the buff on the caster, used for self-cast abilties or abilities that affect the raid (e.g. Divine Sacrifice)

local spells = {
	PALADIN = {
		-- Hand of Freedom
		["1044"] = {
			cooldown = 25,
		},
		-- Hand of Protection
		["10278"] = {
			cooldown = 300,
		},
		-- Hand of Sacrifice
		["6940"] = {
			cooldown = 120,
		},
		-- Hand of Salvation
		["1038"] = {
			cooldown = 120,
		},
		-- Blessing of Kings
		["20217"] = {
			cooldown = 0,
		},
		-- Blessing of Might
		["48932"] = {
			cooldown = 0,
		},
		-- Blessing of Sanctuary
		["20911"] = {
			cooldown = 0,
		},
		-- Blessing of Wisdom
		["48936"] = {
			cooldown = 0,
		},
		-- Greater Blessing of Kings
		["25898"] = {
			cooldown = 0,
		},
		-- Greater Blessing of Might
		["25782"] = {
			cooldown = 0,
		},
		-- Greater Blessing of Sanctuary
		["25899"] = {
			cooldown = 0,
		},
		-- Greater Blessing of Wisdom
		["25894"] = {
			cooldown = 0,
		},
		-- Seal of Command
		["20375"] = {
			cooldown = 0,
		},
		-- Seal of Justice
		["20164"] = {
			cooldown = 0,
		},
		-- Seal of Light
		["20165"] = {
			cooldown = 0,
		},
		-- Seal of Righteousness
		["21084"] = {
			cooldown = 0,
		},
		-- Seal of Vengeance
		["31801"] = {
			cooldown = 0,
		},
		-- Seal of Corruption
		["53736"] = {
			cooldown = 0,
		},
		-- Seal of Wisdom
		["20166"] = {
			cooldown = 0,
		},
		-- Judgement of Justice
		["53407"] = {
			cooldown = 10,
		},
		-- Judgement of Light
		["20271"] = {
			cooldown = 10,
		},
		-- Judgement of Wisdom
		["53408"] = {
			cooldown = 10,
		},
		-- Judgements of the Pure
		["53671"] = {
			cooldown = 0,
		},
		-- Sacred Shield
		["53601"] = {
			cooldown = 0,
		},
		-- Sacred Shield (FIXME: proc, no 100% sure though)
		["58597"] = {
			cooldown = 0,
		},
		-- Aura Mastery
		["31821"] = {
			cooldown = 120,
			trackSelf = true,
		},
		-- Divine Plea
		["54428"] = {
			cooldown = 60,
		},
		-- Beacon of Light
		["53563"] = {
			cooldown = 0,
		},
		-- Infusion of Light
		["53672"] = {
			cooldown = 0,
		},
		-- Light's Grace
		["31834"] = {
			cooldown = 0,
		},
		-- Divine Illumination
		["31842"] = {
			cooldown = 180,
		},
		-- Divine Favor
		["20216"] = {
			cooldown = 120,
		},
		-- Avenging Wrath
		["31884"] = {
			cooldown = 180,
		},
		-- Divine Protection
		["498"] = {
			cooldown = 180,
		},
		-- Divine Shield
		["642"] = {
			cooldown = 300,
		},
		-- Reckoning
		["20177"] = {
			cooldown = 0,
		},
		-- The Art of War
		["53486"] = {
			cooldown = 0,
		},
		-- Holy Shield
		["20925"] = {
			cooldown = 8,
		},
		-- Hammer of Justice
		["853"] = {
			cooldown = 60,
		},
		-- Repentance
--		["20066"] = {
--			cooldown = 60,
--		},
		-- Righteous Vengeance
		["53380"] = {
			cooldown = 0,
		},
		-- Consecration
		["26573"] = {
			cooldown = 8,
		},
		-- Exorcism
		["879"] = {
			cooldown = 15,
		},
		-- Divine Sacrifice
		["64205"] = {
			trackSelf = true,
			cooldown = 120,
		},
		-- Divine Guardian
		["70940"] = {
			trackSelf = true,
			cooldown = 0,
		},
		-- Redoubt
		["20127"] = {
			cooldown = 0,
		},
		-- Turn Evil
		["10326"] = {
			cooldown = 0,
		},
		-- Vengeance
		["20049"] = {
			cooldown = 0,
		},
		-- Heart of the Crusader
		["20335"] = {
			cooldown = 0,
		},
		-- Righteous Vengeance
		["53380"] = {
			cooldown = 0,
		},
		-- Holy Vengeance
		["31803"] = {
			cooldown = 0,
		},
		-- Vindication
		["9452"] = {
			cooldown = 0,
		},
	},
	-- Just testing for now
	WARLOCK = {
		["5697"] = {
			cooldown = 0,
		},
		["706"] = {
			cooldown = 0,
		},
	},
	MAGE = {
		-- FIXME: just for testing
		-- Frost Armor rank 2
		["7300"] = {
			cooldown = 0,
		},
		-- Arcane Intellect rank 2
		["1460"] = {
			cooldown = 0,
		},
	},
--[[		PRIEST = {
			-- Guardian Spirit
			["47788"] = {
				cooldown = 180,
			},
		},
		DRUID = {
			-- Barkskin
			["22812"] = {
				cooldown = 60,
				trackSelf = true,
			},
			-- Survival Instincts
			["61336"] = {
				cooldown = 180,
				trackSelf = true,
			},
		},
		WARRIOR = {
			-- Shield Wall
			["871"] = {
				cooldown = 300, -- 4 min with talents
				trackSelf = true,
			},
			-- Last Stand
			["12975"] = {
				cooldown = 180, -- 2 min with glyph
				trackSelf = true,
			},
		},
	},
]]
	racial = {
	},
	item = {
		-- Energized
		["67696"] = {
			cooldown = 0,
			info = "Solace of the Fallen (245)",
		},
		-- Energized
		["67750"] = {
			cooldown = 0,
			info = "Solace of the Fallen (258)",
		},
		-- Hospitality
		["67684"] = {
			cooldown = 0,
			info = "Talisman of Resurgence",
		},
		-- Blessing of Ancient Kings
		["64411"] = {
			cooldown = 0,
			info = "Val'anyr",
		},
	},
	other = {
	},
}

Wheel.spells = spells

function Wheel:AddSpell(class, id)
	local t = spells[class]
	if not t then return end

	if t[id] then
		if not self.db.profile.spells then
			self.db.profile.spells = {}
		end
		if not self.db.profile.spells[id] then
			self.db.profile.spells[id] = {}
		end
		if not self.db.profile.spells[id].class then
			self.db.profile.spells[id].class = class
		end
		if not self.db.profile.spells[id].name then
			self.db.profile.spells[id].name = GetSpellInfo(id)
		end
		if not self.db.profile.spells[id].cooldown then
			self.db.profile.spells[id].cooldown = t[id].cooldown
		end
		if not self.db.profile.spells[id].trackSelf and t[id].trackSelf then
			self.db.profile.spells[id].trackSelf = t[id].trackSelf
		end
		if not self.db.profile.spells[id].info then
			self.db.profile.spells[id].info = t[id].info
		end
	end
end

function Wheel:AddSpellClass(class)
	for id in pairs(spells[class]) do
		self:AddSpell(class, id)
	end
end

function Wheel:EnableSpell(id, enable)
	local spelldb = self.db.profile.spells[id]
	if not spelldb then return end

	spelldb.enabled = enable
end

function Wheel:EnableSpellClass(class, enable)
	for id in pairs(spells[class]) do
		self:EnableSpell(id, enable)
	end
end

function Wheel:GetRuleIndex(spell, rule_source_id, rule_source_name, rule_target_id, rule_target_name)
	-- Unique index
	local index = spell
	if rule_source_id then
		index = index.."-"..rule_source_id
	end
	if rule_source_name then
		index = index.."-"..rule_source_name
	end
	if rule_target_id then
		index = index.."-"..rule_target_id
	end
	if rule_target_name then
		index = index.."-"..rule_target_name
	end

	return index
end

-- groupType = "aura" or "cooldown"
function Wheel:AddSpellToGroup(id, group, groupType, rule_source_id, rule_source_name, rule_target_id, rule_target_name, announce_start, announce_end, announce_channel0, announce_channel1)
	local spellid = tostring(id)
	local spelldb = self.db.profile.spells[spellid]
	if not spelldb then return end

	local groupdb = self.db.profile.groups[group]
	if not groupdb then return end

	local t
	if groupType == "aura" then
		t = "aura_groups"
	elseif groupType == "cooldown" then
		t = "cooldown_groups"
	else
		return
	end
	if not spelldb[t] then
		spelldb[t] = {}
	end
	spelldb[t][group] = true

	if not groupdb.spells then
		groupdb.spells = {}
	end

	if not groupdb.spells[spellid] then
		groupdb.spells[spellid] = {}
	end

	-- Unique index
	local index = self:GetRuleIndex(spellid, rule_source_id, rule_source_name, rule_target_id, rule_target_name)

	local tbl = {}
	tbl.rule_source_id = rule_source_id or "None"
	tbl.rule_source_name = rule_source_name or "None"
	tbl.rule_target_id = rule_target_id or "None"
	tbl.rule_target_name = rule_target_name or "None"
	tbl.announce_start = announce_start
	tbl.announce_end = announce_end
	tbl.announce_channel0 = announce_channel0
	tbl.announce_channel1 = announce_channel1

	groupdb.spells[spellid][index] = tbl
end

-------------------------
--   Group functions   --
-------------------------

function Wheel:AddGroupSetting_Spell(group, spell)
	local db = self.db.profile.groups[group]

	if not db.spells then
		db.spells = {}
	end

	db.spells[spell] = true
end

function Wheel:AddGroupSetting_SourceID(group, sourceid)
	local db = self.db.profile.groups[group]

	if not db.sourceid then
		db.sourceid = {}
	end

	db.sourceid[sourceid] = true
end

function Wheel:AddGroupSetting_Sourcename(group, sourcename)
	local db = self.db.profile.groups[group]

	if not db.sourcename then
		db.sourcename = {}
	end

	db.sourcename[sourcename] = true
end

function Wheel:AddGroupSetting_SourceID(group, targetid)
	local db = self.db.profile.groups[group]

	if not db.targetid then
		db.targetid = {}
	end

	db.targetid[targetid] = true
end

function Wheel:AddGroupSetting_Sourcename(group, targetname)
	local db = self.db.profile.groups[group]

	if not db.targetname then
		db.targetname = {}
	end

	db.targetname[targetname] = true
end

------------------------
--   Rule functions   --
------------------------

function Wheel:CreateRule(group, rule)
	local db = self.db.profile.groups[group]

	if not db.rules then
		db.rules = {}
	end

	db.rules[rule] = {}
end

function Wheel:AddSpellClassToRule(group, rule,  spellclass)
	local db = self.db.profile.groups[group].rules[rule]

	if not db.spellclass then
		db.spellclass = {}
	end

	db.spellclass[spellclass] = true
end

function Wheel:AddSpellIDToRule(group, rule,  spellid)
	local db = self.db.profile.groups[group].rules[rule]

	if not db.spellid then
		db.spellid = {}
	end

	db.spellid[spellid] = true
end

function Wheel:AddSourceNameToRule(group, rule, sourcename)
	local db = self.db.profile.groups[group].rules[rule]

	if not db.sourcename then
		db.sourcename = {}
	end

	db.sourcename[sourcename] = true
end

function Wheel:AddSourceIDToRule(group, rule, sourceid)
	local db = self.db.profile.groups[group].rules[rule]

	if not db.sourceid then
		db.sourceid = {}
	end

	db.sourceid[sourceid] = true
end

function Wheel:AddTargetNameToRule(group, rule, targetname)
	local db = self.db.profile.groups[group].rules[rule]

	if not db.targetname then
		db.targetname = {}
	end

	db.targetname[targetname] = true
end

function Wheel:AddTargetIDToRule(group, rule, targetid)
	local db = self.db.profile.groups[group].rules[rule]

	if not db.targetid then
		db.targetid = {}
	end

	db.targetid[targetid] = true
end

--[[function Wheel:CreateAnnounce(spellid)
	local t = {}

	t.enablerule = "general"
	t.enablezone_world = nil
	t.enablezone_bg = nil
	t.enablezone_arena = nil
	t.enablezone_partyinstance = nil
	t.enablezone_raidinstance = true

	self.db.profile.announces[spellid] = t
end

function Wheel:AddAnnounceStartToSpell(spellid, announce_start)
	self.db.profile.announces[spellid].announce_start = announce_start
end

function Wheel:AddAnnounceEndToSpell(spellid, announce_end)
	self.db.profile.announces[spellid].announce_end = announce_end
end

function Wheel:AddAnnounceChannelsToRule(spellid, announce_channel0, announce_channel1)
	self.db.profile.announces[spellid].announce_channel0 = announce_channel0
	self.db.profile.announces[spellid].announce_channel1 = announce_channel1
end
]]
function Wheel:ResetSpells()
	self.db.profile.spells = {}
	for k, v in pairs(spells) do
		self:AddSpellClass(k)
	end
end

function Wheel:ValidateRule(group, spellid, sourceid, sourcename, targetid, targetname)
--	print("ValidateRule: "..group.." - "..spellid.." - "..sourcename)

	local spelldb = self.db.profile.spells[spellid]

	local db = self.db.profile.groups[group]
--	if not db.spells then
--		return
--	end

--	local sets = db.spells[tostring(spellid)]

	local rules = self.db.profile.groups[group].rules
	local result
	for index, rule in pairs(rules) do

		-- First check spell
		result = nil
		if rule.spellid and rule.spellid[spellid] then
			result = true
		end
		if not result and rule.spellclass and rule.spellclass[spelldb.class] then
			result = true
		end

		if result then

			result = nil
			if rule.sourcename then
				for name in pairs(rule.sourcename) do
					if name == sourcename then
						result = true
						break
					end
				end
			end
			if not result and rule.sourceid then
				for id in pairs(rule.sourceid) do
--					print("sourceid: "..id)
					if UnitIsUnit(id, sourceid) or (id == "any") or (id == "other" and not UnitIsUnit(sourceid, "player")) then
						result = true
						break
					end
				end
			end

			if result then
				result = nil
				if rule.targetname then
					for name in pairs(rule.targetname) do
						if name == targetname then
							result = true
							break
						end
					end
				end
				if not result and rule.targetid then
					for id in pairs(rule.targetid) do
--						print("targetid: "..id)
						if UnitIsUnit(id, targetid) or (id == "any") or (id == "other" and not UnitIsUnit(targetid, "player")) then
							result = true
							break
						end
					end
				end
			end
		end

		if result then
			result = index
			break
		end
	end

	return result
end

function Wheel:Dummy2()

--[[	self:InitializeGroup("test")
	self:CreateRule("test", "testrule")
	self:AddSpellClassToRule("test", "testrule", "PALADIN")
	self:AddSpellClassToRule("test", "testrule", "WARLOCK")
	self:AddSpellClassToRule("test", "testrule", "MAGE")
	self:AddSourceIDToRule("test", "testrule", "player")
	self:AddTargetIDToRule("test", "testrule", "any")
]]

--[[	self:InitializeGroup("player")
	self:InitializeGroup("target")
	self:InitializeGroup("ssbolmine")
	self:InitializeGroup("ssbolother")

	self:CreateRule("player", "testrule")
	self:AddSpellClassToRule("player", "testrule", "PALADIN")
	self:AddSpellClassToRule("player", "testrule", "WARLOCK")
	self:AddSourceIDToRule("player", "testrule", "player")
	self:AddTargetIDToRule("player", "testrule", "player")
]]
--[[
	self:CreateAnnounce("Aura Mastery")
	self:AddAnnounceStartToSpell("Aura Mastery", "+++ Aura Mastery up +++")
	self:AddAnnounceEndToSpell("Aura Mastery", "--- Aura Mastery ends ---")
	self:AddAnnounceChannelsToRule("Aura Mastery", 5, 6)
	self:CreateAnnounce("Hand of Freedom")

	self:AddAnnounceStartToSpell("Hand of Freedom", "+++ Hand of Freedom on $t +++")
	self:AddAnnounceEndToSpell("Hand of Freedom", "--- Hand of Freedom ends on $t ---")
	self:AddAnnounceChannelsToRule("Hand of Freedom", 5, 6)

	self:CreateAnnounce("Demon Armor")
	self:AddAnnounceStartToSpell("Demon Armor", "+++ Demon Armor on $t +++")
	self:AddAnnounceEndToSpell("Demon Armor", "--- Demon Armor ends on $t ---")
--	self:AddAnnounceChannelsToRule("Hand of Freedom", 5, 6)
]]
--[[	self:CreateRule("target", "testrule")
	self:AddSpellClassToRule("target", "testrule", "PALADIN")
	self:AddSourceIDToRule("target", "testrule", "player")
	self:AddTargetIDToRule("target", "testrule", "target")

	self:CreateRule("ssbolmine", "testrule")
	self:AddSpellIDToRule("ssbolmine", "testrule", "53601")
	self:AddSpellIDToRule("ssbolmine", "testrule", "53563")
	self:AddSourceIDToRule("ssbolmine", "testrule", "player")
	self:AddTargetIDToRule("ssbolmine", "testrule", "any")

	self:CreateRule("ssbolother", "testrule")
	self:AddSpellIDToRule("ssbolother", "testrule", "53601")
	self:AddSpellIDToRule("ssbolother", "testrule", "53563")
	self:AddSourceIDToRule("ssbolother", "testrule", "other")
	self:AddTargetIDToRule("ssbolother", "testrule", "any")
]]
end


function Wheel:DummyInit()

	self:Dummy2()

	self:AddSpellClass("PALADIN")
	self:EnableSpellClass("PALADIN", true)
	-- Testing (warlock)
	self:AddSpellClass("WARLOCK")
	self:EnableSpellClass("WARLOCK", true)
	-- Testing (mage)
	self:AddSpellClass("MAGE")
	self:EnableSpellClass("MAGE", true)
--	self:EnableSpell("class", "WARLOCK", 5697)
--	self:EnableSpell("class", "WARLOCK", 706)
--	self:AddSpellClass("item")
--	self:EnableSpellClass("item", true)

	-- Sacred Shield
	self:AddSpellToGroup(53601, "ssbolmine", "aura", "player", nil, "any")
	-- Sacred Shield
	self:AddSpellToGroup(53601, "ssbolother", "aura", "other", "any")

	-- Beacon of Light
	self:AddSpellToGroup(53563, "ssbolmine", "aura", "player", nil, "any")
	-- Beacon of Light
	self:AddSpellToGroup(53563, "ssbolother", "aura", "other", nil, "any")

	-- Beacon of Light
	self:AddSpellToGroup(53563, "player", "aura", "player", nil, "player")
	-- Sacred Shield
	self:AddSpellToGroup(53601, "player", "aura", "player", nil, "player")
	-- Aura Mastery
	self:AddSpellToGroup(31821, "player", "aura", "player", nil, "player", nil, "+++ Aura Mastery up +++", "--- Aura Mastery ends ---", 5, 6)
	-- Hand of Freedom
	self:AddSpellToGroup(1044, "player", "aura", "player", nil, "player", nil)
	-- Divine Sacrifice
	self:AddSpellToGroup(64205, "player", "aura", "player", nil, "player", nil)
	-- Divine Guardian
	self:AddSpellToGroup(70940, "player", "aura", "player", nil, "player", nil, "+++ Divine Guardian up +++", "--- Divine Gurdian ends ---", 5, 6)
	-- Sacred Shield (proc)
	self:AddSpellToGroup(58597, "player", "aura", "player", nil, "player", nil)
	-- Divine Plea
	self:AddSpellToGroup(54428, "player", "aura", "player", nil, "player", nil)
	-- Divine Shield
	self:AddSpellToGroup(642, "player", "aura", "player", nil, "player", nil)
	-- Hand of Protection
	self:AddSpellToGroup(10278, "player", "aura", "player", nil, "player", nil)
	-- Light's Grace
	self:AddSpellToGroup(31834, "player", "aura", "player", nil, "player", nil)
	-- Judgements of the Pure
	self:AddSpellToGroup(53671, "player", "aura", "player", nil, "player", nil)
	-- Solace of the Fallen
	self:AddSpellToGroup(67696, "player", "aura", "player", nil, "player", nil)

	-- Seals
	self:AddSpellToGroup(20375, "player", "aura", "player", nil, "player", nil)
	self:AddSpellToGroup(20164, "player", "aura", "player", nil, "player", nil)
	self:AddSpellToGroup(20165, "player", "aura", "player", nil, "player", nil)
	self:AddSpellToGroup(21084, "player", "aura", "player", nil, "player", nil)
	self:AddSpellToGroup(31801, "player", "aura", "player", nil, "player", nil)
	self:AddSpellToGroup(53736, "player", "aura", "player", nil, "player", nil)
	self:AddSpellToGroup(20166, "player", "aura", "player", nil, "player", nil)

	-- Testing (warlock)
--	self:AddSpellToGroup(5697, "player", "aura", "player", "player")
--	self:AddSpellToGroup(706, "player", "aura", "player", "player")
end

function Wheel:IsValidSpell(spell)
	local found

	for class, t in pairs(spells) do
		for id in pairs(t) do
			if GetSpellInfo(id) == spell then
				found = true
				break
			end

			if found then
				break
			end
		end
		if found then
			break
		end
	end

	return found
end


